package com.daniel.juc.add;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 独占锁（写锁），一次只能被一个线程占有
 * 共享锁（读锁），多个线程可以同时占有
 * ReadWriteLock
 * 读-读 可以共存
 * 读-写 不能共存
 * 写-写 不能共存
 *
 * @author Daniel
 * @version V1.0
 * @date 2020/5/20 17:36
 */
public class ReadWriteLockDemo {
	public static void main(String[] args) {
		MyCacheLock myCache = new MyCacheLock();
		// 写入
		for (int i = 1; i <= 5; i++) {
			final int temp = i;
			new Thread(() -> {
				myCache.put(temp + "", temp + "");
			}, String.valueOf(i)).start();
		}

		// 读取
		for (int i = 1; i <= 5; i++) {
			final int temp = i;
			new Thread(() -> {
				myCache.get(temp + "");
			}, String.valueOf(i)).start();
		}
	}
}

class MyCacheLock {
	private volatile Map<String, Object> map = new HashMap<>();

	/**
	 * 读写锁，更加细粒度的控制
	 */
	private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

	/**
	 * 存，写入的时候，只有一个线程在操作
	 *
	 * @param key
	 * @param value
	 */
	public void put(String key, Object value) {
		readWriteLock.writeLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + "写入" + key);
			map.put(key, value);
			System.out.println(Thread.currentThread().getName() + "写入OK");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			readWriteLock.writeLock().unlock();
		}
	}

	/**
	 * 取，所有人都可以读取
	 *
	 * @param key
	 */
	public void get(String key) {
		readWriteLock.readLock().lock();
		try {
			System.out.println(Thread.currentThread().getName() + "读取" + key);
			map.get(key);
			System.out.println(Thread.currentThread().getName() + "读取OK");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			readWriteLock.readLock().unlock();
		}
	}
}

class MyCache {
	private volatile Map<String, Object> map = new HashMap<>();

	/**
	 * 存，写
	 *
	 * @param key
	 * @param value
	 */
	public void put(String key, Object value) {
		System.out.println(Thread.currentThread().getName() + "写入" + key);
		map.put(key, value);
		System.out.println(Thread.currentThread().getName() + "写入OK");
	}

	/**
	 * 取，读
	 *
	 * @param key
	 */
	public void get(String key) {
		System.out.println(Thread.currentThread().getName() + "读取" + key);
		map.get(key);
		System.out.println(Thread.currentThread().getName() + "读取OK");
	}
}
